package com.ruoyi.merchant.service.impl;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.QrCodeUtil;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.SmartParkingCloudConfig;
import com.ruoyi.framework.config.WxPayConfig;
import com.ruoyi.merchant.domain.MerchantCouponIssue;
import com.ruoyi.merchant.domain.MerchantCouponOrder;
import com.ruoyi.merchant.domain.MerchantPlatformCoupon;
import com.ruoyi.merchant.domain.MerchantUser;
import com.ruoyi.merchant.mapper.MerchantCouponIssueMapper;
import com.ruoyi.merchant.mapper.MerchantCouponOrderMapper;
import com.ruoyi.merchant.mapper.MerchantPlatformCouponMapper;
import com.ruoyi.merchant.mapper.MerchantUserMapper;
import com.ruoyi.merchant.other.dto.ConfirmPaymentDto;
import com.ruoyi.merchant.other.dto.CouponCollectionDto;
import com.ruoyi.merchant.other.dto.CouponQrCodeDto;
import com.ruoyi.merchant.other.mapper.CouponOrderMapper;
import com.ruoyi.merchant.other.mapper.PlatformCouponMapper;
import com.ruoyi.merchant.other.vo.MerchantCouponVo;
import com.ruoyi.merchant.other.vo.PlatformCouponVo;
import com.ruoyi.merchant.service.IMerchantAppService;
import com.wechat.pay.java.core.cipher.RSASigner;
import com.wechat.pay.java.service.payments.jsapi.JsapiService;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;

/**
 * 商家信息Service业务层处理
 * 
 * @author dongdong
 * @date 2025-10-21
 */

@Slf4j
@Service
public class MerchantAppServiceImpl implements IMerchantAppService {

    @Autowired
    private RSASigner rsaSigner;
    @Autowired
    private JsapiService jsapiService;
    @Autowired
    private WxPayConfig wxPayConfig;
    @Resource
    private MerchantUserMapper merchantUserMapper;
    @Resource
    private MerchantPlatformCouponMapper merchantPlatformCouponMapper;
    @Resource
    private MerchantCouponOrderMapper merchantCouponOrderMapper;
    @Resource
    private MerchantCouponIssueMapper merchantCouponIssueMapper;

    /**
     * 查询商家信息
     * 
     * @param username 账号
     * @param password 密码
     * @return 商家信息
     */
    @Override
    public MerchantUser login(String username, String password) {
        // 查询用户
        MerchantUser merchantUser = merchantUserMapper.selectMerchantUserByUsername(username);
        if (merchantUser == null) {
            throw new RuntimeException("用户不存在");
        }

        // 检查状态
        if (merchantUser.getStatus() != null && merchantUser.getStatus() == 1) {
            throw new RuntimeException("账号已停用，请联系管理员");
        }

        // 验证密码
        if (!password.equals(merchantUser.getPassword())) {
            throw new RuntimeException("用户名或密码错误");
        }
        merchantUser.setPassword(null);
        return merchantUser;
    }

    @Override
    public List<PlatformCouponVo> couponList(String search, Long merchantId) {
        List<MerchantPlatformCoupon> merchantPlatformCouponList = merchantPlatformCouponMapper.selectCouponList(merchantId, search);
        List<PlatformCouponVo> list = PlatformCouponMapper.INSTANCE.toPlatformCouponVoList(merchantPlatformCouponList);
        return list;
    }

    @Override
    public PlatformCouponVo getCoupon(Long id) {
        MerchantPlatformCoupon merchantPlatformCoupon = merchantPlatformCouponMapper.selectMerchantPlatformCouponById(id);
        PlatformCouponVo vo = PlatformCouponMapper.INSTANCE.toPlatformCouponVo(merchantPlatformCoupon);
        return vo;
    }

    @Override
    public MerchantCouponVo couponIssueInfo(String orderNo) {
        MerchantCouponOrder merchantCouponOrder = merchantCouponOrderMapper.selectMerchantCouponOrderByOrderNo(orderNo);
        MerchantCouponVo vo = CouponOrderMapper.INSTANCE.toMerchantCouponVo(merchantCouponOrder);
        return vo;
    }

    @Override
    @Transactional
    public Map<String, String> confirmPayment(ConfirmPaymentDto confirmPaymentDto) {
        MerchantPlatformCoupon coupon = merchantPlatformCouponMapper.selectMerchantPlatformCouponById(confirmPaymentDto.getCouponId());
        MerchantUser merchant = merchantUserMapper.selectMerchantUserById(confirmPaymentDto.getMerchantId());
        MerchantCouponOrder merchantCouponOrder = new MerchantCouponOrder();
        String orderNo = StringUtils.getOrderNo("MCD");
        merchantCouponOrder.setOrderNo(orderNo);
        merchantCouponOrder.setMerchantId(merchant.getId());
        merchantCouponOrder.setCouponId(coupon.getId());
        merchantCouponOrder.setCouponName(coupon.getCouponName());
        merchantCouponOrder.setOrderStatus(2);
        merchantCouponOrder.setTotalFaceValue(coupon.getFaceValue());
        merchantCouponOrder.setActualAmount(coupon.getActualPrice());
        merchantCouponOrder.setUniqueId(confirmPaymentDto.getUniqueId());
        merchantCouponOrder.setIssueNum(0);
        merchantCouponOrder.setIssueAmount(new BigDecimal(0));
        merchantCouponOrder.setNotIssueAmount(coupon.getFaceValue());
        merchantCouponOrder.setCreateTime(new Date());
        merchantCouponOrderMapper.insertMerchantCouponOrder(merchantCouponOrder);

        confirmPaymentDto.setBody(coupon.getCouponName());
        confirmPaymentDto.setAmount(coupon.getActualPrice().multiply(BigDecimal.valueOf(100)).intValue());
        return weChatPay(orderNo, confirmPaymentDto);
    }

    @Override
    public List<MerchantCouponVo> merchantCouponList(Integer status, Long merchantId) {
        List<MerchantCouponVo> couponOrderList = merchantCouponOrderMapper.selectCouponOrderList(status, merchantId);
        return couponOrderList;
    }

    @Override
    public Map<String, Object> createQrCode(CouponQrCodeDto couponQrCodeDto) {
        Map<String, Object> rtnMap = new HashMap<>();
        rtnMap.put("key", Boolean.FALSE);
        BigDecimal amount = couponQrCodeDto.getAmount();
        if(Objects.isNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0){
            rtnMap.put("value", "无效的优惠金额");
            return rtnMap;
        }else {
            String orderNo = couponQrCodeDto.getOrderNo();
            MerchantCouponOrder merchantCouponOrder = merchantCouponOrderMapper.selectMerchantCouponOrderByOrderNo(orderNo);
            if(Objects.isNull(merchantCouponOrder)){
                rtnMap.put("value", "无效的订单号");
                return rtnMap;
            }
            if (merchantCouponOrder.getOrderStatus().intValue() != 3) {
                rtnMap.put("value", "订单状态异常");
                return rtnMap;
            }
            if(merchantCouponOrder.getNotIssueAmount().compareTo(amount) < 0){
                rtnMap.put("value", "优惠券额度不足，剩余额度："+ merchantCouponOrder.getNotIssueAmount());
                return rtnMap;
            }
            Long timestamp = System.currentTimeMillis() / 1000;
            String content = "https://zhtc.lssmartcity.com/app/merchant/couponQrCode?orderNo="+orderNo+"&amount="+amount+"&v="+timestamp;
            rtnMap.put("key", Boolean.TRUE);
            rtnMap.put("value", content);
            return rtnMap;
        }
    }

    @Override
    public void couponQrCode(String orderNo, String amount, HttpServletResponse response) throws Exception {
        Long timestamp = System.currentTimeMillis() / 1000;
        String content = "https://app.lssmartcity.com/merchant/#/pages/muIndex?amount="+amount+"&tamp="+orderNo+timestamp;
        QrCodeUtil.generateToResponse(content, response);
    }

    @Override
    public String verifyQrCode(String tamp) {
        if(Objects.isNull(tamp) || tamp.length() != 30){
            return "无效的优惠券";
        }
        String times = tamp.substring(tamp.length() - 10, tamp.length());
        // 判断是否超过2分钟（120秒）
        Long timestamp = Long.parseLong(times);
        Long timestamp1 = System.currentTimeMillis() / 1000;
        if (Math.abs(timestamp1 - timestamp) > 120) {
            return "二维码已失效";
        }
        String orderNo = tamp.substring(0, tamp.length() - 10);
        MerchantCouponOrder merchantCouponOrder = merchantCouponOrderMapper.selectMerchantCouponOrderByOrderNo(orderNo);
        if (Objects.isNull(merchantCouponOrder)) {
            return "无效的二维码";
        }
        MerchantCouponIssue merchantCouponIssue = merchantCouponIssueMapper.selectMerchantCouponIssueByCouponCode(tamp);
        if (Objects.nonNull(merchantCouponIssue)) {
            if(merchantCouponIssue.getStatus().intValue() == 1){
                return "该优惠券已使用";
            }else if(merchantCouponIssue.getStatus().intValue() == 2){
                return "该优惠券已过期";
            }else {
                return "该优惠券已被领取";
            }
        }
        return "";
    }

    /**
     * 优惠券领取 实现逻辑
     * 1、先判断优惠券是否正确 订单号 + 生成二维码的时间戳（MCD202510271717572541761724992）
     * 2、再通过券码tamp查询是否使用
     * 3、查询优惠券订单是否存在
     * 4、通过车牌号+优惠券id 查询车辆是否有入场记录
     * 5、如果有入场记录，则进行优惠券领取，创建发放信息
     * 注：再停车缴费时查询用户优惠券，若优惠金额超出停车缴费金额，则把超出金额返还至商户账户
     */
    @Override
    @Transactional
    public Boolean couponCollection(CouponCollectionDto couponCollectionDto) {
        String tamp = couponCollectionDto.getTamp();
        if(Objects.isNull(tamp) || tamp.length() != 30){
            log.error("无效的优惠券，优惠券码：{}", tamp);
            throw new RuntimeException("无效的优惠券");
        }
        MerchantCouponIssue merchantCouponIssue = merchantCouponIssueMapper.selectMerchantCouponIssueByCouponCode(tamp);
        if (Objects.nonNull(merchantCouponIssue)) {
            if(merchantCouponIssue.getStatus().intValue() == 1){
                throw new RuntimeException("该优惠券已使用");
            }else if(merchantCouponIssue.getStatus().intValue() == 2){
                throw new RuntimeException("该优惠券已过期");
            }else {
                throw new RuntimeException("该优惠券已被领取");
            }
        }
        String orderNo = tamp.substring(0, tamp.length() - 10);
        MerchantCouponOrder merchantCouponOrder = merchantCouponOrderMapper.selectMerchantCouponOrderByOrderNo(orderNo);
        if (Objects.isNull(merchantCouponOrder)) {
            log.error("无效的优惠券，优惠券码：{}", tamp);
            throw new RuntimeException("无效的优惠券");
        }
        String recordId = merchantCouponIssueMapper.selectParkingRecordInByCarNum(couponCollectionDto.getCarNum(), merchantCouponOrder.getCouponId());

        if(StringUtils.isBlank(recordId)){
            log.error("未查询到车辆入场记录，车牌号：{}", couponCollectionDto.getCarNum());
            throw new RuntimeException("未查询到车辆入场记录");
        }
        MerchantCouponIssue cIssue = merchantCouponIssueMapper.selectMerchantCouponIssueByRecordId(recordId);
        if(Objects.nonNull(cIssue)){
            throw new RuntimeException(couponCollectionDto.getCarNum()+"已领取过优惠券");
        }
        BigDecimal amount = couponCollectionDto.getAmount();
        MerchantCouponIssue couponIssue = new MerchantCouponIssue();
        couponIssue.setOrderId(merchantCouponOrder.getId());
        couponIssue.setMerchantId(merchantCouponOrder.getMerchantId());
        couponIssue.setCouponCode(tamp);
        couponIssue.setFaceValue(amount);
        couponIssue.setCarNum(couponCollectionDto.getCarNum());
        couponIssue.setParkingRecordId(recordId);
        couponIssue.setStatus(0);
        couponIssue.setQrCodeUrl(couponCollectionDto.getQrCodeUrl());
        Date now = new Date();
        couponIssue.setValidStartTime(now);
        couponIssue.setValidEndTime(DateUtils.addMinutes(now, 30));
        couponIssue.setCreateTime(now);
        couponIssue.setUpdateTime(now);
        int resIssue = merchantCouponIssueMapper.insertMerchantCouponIssue(couponIssue);
        if (resIssue != 1){
            throw new RuntimeException("优惠券领取失败");
        }
        merchantCouponOrder.setIssueAmount(merchantCouponOrder.getIssueAmount().add(amount));
        merchantCouponOrder.setNotIssueAmount(merchantCouponOrder.getNotIssueAmount().subtract(amount));
        merchantCouponOrder.setUpdateTime(now);
        int res = merchantCouponOrderMapper.updateMerchantCouponOrder(merchantCouponOrder);
        if (res != 1){
            throw new RuntimeException("优惠券领取失败");
        }
        return Boolean.TRUE;
    }

    @Override
    public BigDecimal couponIssue(CouponCollectionDto couponCollectionDto) {
        String orderNo = couponCollectionDto.getTamp();
        MerchantCouponOrder merchantCouponOrder = merchantCouponOrderMapper.selectMerchantCouponOrderByOrderNo(orderNo);
        if (Objects.isNull(merchantCouponOrder)) {
            log.error("无效的优惠券订单，订单号：{}", orderNo);
            throw new RuntimeException("无效的优惠券");
        }
        String recordId = merchantCouponIssueMapper.selectParkingRecordInByCarNum(couponCollectionDto.getCarNum(), merchantCouponOrder.getCouponId());

        if(StringUtils.isBlank(recordId)){
            log.error("未查询到车辆入场记录，车牌号：{}", couponCollectionDto.getCarNum());
            throw new RuntimeException(couponCollectionDto.getCarNum()+"无在停记录");
        }
        MerchantCouponIssue cIssue = merchantCouponIssueMapper.selectMerchantCouponIssueByRecordId(recordId);
        if(Objects.nonNull(cIssue)){
            throw new RuntimeException(couponCollectionDto.getCarNum()+"已领取过优惠券");
        }
        Long timestamp = System.currentTimeMillis() / 1000;
        BigDecimal amount = couponCollectionDto.getAmount();
        MerchantCouponIssue couponIssue = new MerchantCouponIssue();
        couponIssue.setOrderId(merchantCouponOrder.getId());
        couponIssue.setMerchantId(merchantCouponOrder.getMerchantId());
        couponIssue.setCouponCode(orderNo + timestamp);
        couponIssue.setFaceValue(amount);
        couponIssue.setCarNum(couponCollectionDto.getCarNum());
        couponIssue.setParkingRecordId(recordId);
        couponIssue.setStatus(0);
        couponIssue.setQrCodeUrl(couponCollectionDto.getQrCodeUrl());
        Date now = new Date();
        couponIssue.setValidStartTime(now);
        couponIssue.setValidEndTime(DateUtils.addMinutes(now, 30));
        couponIssue.setCreateTime(now);
        couponIssue.setUpdateTime(now);
        int resIssue = merchantCouponIssueMapper.insertMerchantCouponIssue(couponIssue);
        if (resIssue != 1){
            throw new RuntimeException("优惠券发放失败");
        }
        BigDecimal notIssueAmount = merchantCouponOrder.getNotIssueAmount().subtract(amount);
        merchantCouponOrder.setIssueAmount(merchantCouponOrder.getIssueAmount().add(amount));
        merchantCouponOrder.setNotIssueAmount(notIssueAmount);
        merchantCouponOrder.setUpdateTime(now);
        int res = merchantCouponOrderMapper.updateMerchantCouponOrder(merchantCouponOrder);
        if (res != 1){
            throw new RuntimeException("优惠券发放失败");
        }
        return notIssueAmount;
    }

    /**
     * 微信支付
     * @param confirmPaymentDto
     * @return
     */
    public Map<String, String> weChatPay(String orderNo, ConfirmPaymentDto confirmPaymentDto) {
        String appId = SmartParkingCloudConfig.APPID;
        try {
            PrepayRequest request = new PrepayRequest();

            // 设置金额
            Amount amount = new Amount();
            amount.setTotal(confirmPaymentDto.getAmount());
            request.setAmount(amount);

            // 设置支付者
            Payer payer = new Payer();
            payer.setOpenid(confirmPaymentDto.getUniqueId());
            request.setPayer(payer);

            // 设置基本参数
            request.setAppid(appId);
            request.setMchid(wxPayConfig.getMchId());
            request.setDescription(confirmPaymentDto.getBody());
            request.setNotifyUrl(wxPayConfig.getMerchantNotifyUrl());
            request.setOutTradeNo(orderNo);

            // 调用预支付
            PrepayResponse response = jsapiService.prepay(request);

            // 返回支付参数
            long timestamp = System.currentTimeMillis() / 1000;
            String nonceStr = UUID.randomUUID().toString().replace("-", "");
            String packageStr = "prepay_id=" + response.getPrepayId();

            // 构造签名字符串
            String message = appId + "\n" +
                    timestamp + "\n" +
                    nonceStr + "\n" +
                    packageStr + "\n";

            // 生成签名
            String paySign = rsaSigner.sign(message).getSign();

            Map<String, String> result = new HashMap<>();
            result.put("appId", appId);
            result.put("timeStamp", String.valueOf(timestamp));
            result.put("nonceStr", nonceStr);
            result.put("package", packageStr);
            result.put("signType", "RSA");
            result.put("paySign", paySign);
            return result;
        } catch (Exception e) {
            log.error("{} 微信支付创建失败: {}", orderNo, e.getMessage());
            throw new RuntimeException("支付失败，请联系客服");
        }
    }

}
